#!/usr/local/bin/php

<?php
  require_once('daemons.conf.php');
  require_once('lib/ses.php');
  require_once("lib/db.broker.php");
  require_once("lib/create-daemon.php");

  $db = New broker;

  while (true) {

    if ($signal_code) {
      exit;
    }

    // generamos la lista de campañas que requieren ser enviadas
    // esta lista se actualiza cada vez que se entra al while
    $campaigns_sql  = "
      SELECT 
        campaigns.`id`,
        campaigns.`subject`,
        campaigns.`from`,
        campaigns.`name`,
        campaigns.`body`,
        campaigns.`sent`,
        campaigns.`shipment`
      FROM
        campaigns
      WHERE 
        ((campaigns.shipment = 0) OR (campaigns.shipment > (NOW() - INTERVAL 20 SECOND)))  AND 
        (campaigns.body     > '') AND 
        (campaigns.sent     > 0)
      ORDER BY 
        campaigns.sent
    ";


    // get amazon send's limit
    $ses = new SimpleEmailService(AWS_USER_KEY, AWS_SECRET_KEY);
    $sendQuota         = $ses->getSendQuota();

    // Forzamos la frecuencia de envio a XX emails por segundo
    $sendQuota['MaxSendRate'] = 20;

    $AWSSendRateLimit  = floor(1000 / $sendQuota['MaxSendRate']); // in milliseconds | 1,000 = 1seg
    $AWSMailsRemaining = $sendQuota['Max24HourSend'] - $sendQuota['SentLast24Hours'];

    // Get campaigns to send
    $campaigns = $db->query($campaigns_sql);

    $umbral = $sendQuota['Max24HourSend'] * 0.02 + count($campaigns) * LIMIT_PER_CAMPAIGN;

    // Solo entramos si hay campañas y si nos queda margen de envíos para todas esas campañas
    if (count($campaigns) && ($AWSMailsRemaining > $umbral )) {
      
      // enviamos una tanda de emails por cada campaña
      foreach ($campaigns as $campaign) {

$now = date("Y-m-d H:i:s") . substr((string)microtime(), 1, 8);
error_log("{$now} Campaign: {$campaign['subject']} \r\n", 3, LOG_FILE);

        if ($signal_code) {
          exit;
        }

        // seleccionamos una tanda de destinatarios a los que no se les haya enviado la campaña
        $recipients_sql  = "
          SELECT
            sends.tries,
            sends.sent,
            sends.id as send_id,
            recipients.id as recipient_id,
            recipients.email,
            recipients.firstname,
            recipients.lastname,
            recipients.nickname
          FROM
            sends
          INNER JOIN 
            recipients ON sends.recipient_id = recipients.id
          WHERE 
            ((sends.planned + 10) < UNIX_TIMESTAMP() ) AND
            (sends.campaign_id    = {$campaign['id']}) AND 
            (sends.tries          < 2)                 AND
            (ISNULL(sends.awsmessageid))                
          ORDER BY RAND()
          LIMIT " . LIMIT_PER_CAMPAIGN;

        $recipients = $db->query($recipients_sql);

        // enviamos el emails a los destinatarios elegidos
        // tenemos en cuenta la frecuencia de envios
        if (count($recipients)) {

          // Establecemos la cantidad de tandas de envío paralelo que se hará para cada campaña
          // Ej. con limitpercampaign = 100 y sendQuotaMaxSendRate = 20, tendremos 5 tandas
          $tandas = LIMIT_PER_CAMPAIGN / $sendQuota['MaxSendRate'];

          $i=0; // establecemos un contador para recipients

          while($tandas) {

            // si pasamos la cantidad de emails obtenidos, cortamos el while
            if(!array_key_exists($i,$recipients)) break;

            //create the multiple cURL handle
            $mh = curl_multi_init();
            $ch = array();

            // Vamos a preparar todos los emails de esta tanda para enviarlos en paralelo
            for($j=0; $j < $sendQuota['MaxSendRate']; $j++) {

              // si pasamos la cantidad de emails obtenidos, cortamos el for
              if(!array_key_exists($i,$recipients)) break;

              // obtenemos el recipient actual
              $recipient = $recipients[$i];

              // unsubscribe url
              $body = str_replace('.unsubscribe_key.', $recipient['recipient_id'].'-'.sha1($recipient['recipient_id'] + $campaign['id']).'-'.$campaign['id'], $campaign['body']);

              // read status
              $body = str_replace('.sends_key.', $recipient['send_id'], $body);

              $postdata = array(
                'AWS_SECRET_KEY'  => AWS_SECRET_KEY,
                'to'              => $recipient['email'],
                'from'            => utf8_encode("{$campaign['name']} <{$campaign['from']}>"),
                'subject'         => utf8_encode($campaign['subject']),
                'body'            => htmlspecialchars($body, ENT_QUOTES),
                'send_id'         => $recipient['send_id'],
                'campaign_id'     => $campaign['id']
              );

              $update_sql = "UPDATE `sends` SET `planned`=UNIX_TIMESTAMP() WHERE (`id`= {$recipient['send_id']})";
              $updated    = $db->update($update_sql);

              if ($updated) {

//$now = date("Y-m-d H:i:s") . substr((string)microtime(), 1, 8);
//error_log("{$now} Email To: {$postdata['to']} \r\n", 3, LOG_FILE);

                $ch[$j] = curl_init();
                curl_setopt($ch[$j], CURLOPT_TIMEOUT, 1); // will wait up to XX milliseconds to get response
                curl_setopt($ch[$j], CURLOPT_URL, SENDER_URL);
                curl_setopt($ch[$j], CURLOPT_POST, TRUE);
                curl_setopt($ch[$j], CURLOPT_POSTFIELDS, $postdata);
                curl_multi_add_handle($mh,$ch[$j]);

                $AWSMailsRemaining--; // forzamos la actualización temporal de los emails que AWS nos deja enviar hoy
                if ($AWSMailsRemaining < $sendQuota['Max24HourSend'] * 0.02) {
                  break; // si estamos cerca del umbral, cortamos
                }

                if ($signal_code) {
                  exit;
                }

              } // updated

              $i++; // incrementamos el contador de recipients
                
            } // for j

            //execute the handles
            $running = null;
            do {
              curl_multi_exec($mh,$running);
            } while ($running > 0);

            //close the handles
            foreach ($ch as $instance) {
              curl_multi_remove_handle($mh, $instance);
            }
            curl_multi_close($mh);

            $tandas--; // descontamos la tanda enviada
            
          } // while tandas
        } // count recipients

        // si la campaña ya no tiene emails para enviar, la marcamos como enviada
        else {
          if ($campaign['shipment'] == "0000-00-00 00:00:00") {
            $update_sql = "UPDATE `campaigns` SET `shipment` = NOW() WHERE (`id` = {$campaign['id']})";
            $updated    = $db->update($update_sql);
          }
          sleep(5); // dejamos descansar 5seg el procesador :)
        }

      } // foreach campaigns
    } // if campaigns
    else {

      if ($signal_code) {
        exit;
      }

      sleep(30); // dejamos descansar 30seg el procesador :)
    }
  } // while(true)
